package band.wukong.practice.webservice.util.raw;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

import javax.xml.bind.*;
import java.io.StringWriter;

/**
 * 以主工程里的为准！
 *
 * @author wukong(wukonggg@139.com)
 */
public class JAXBUtil {

    /**
     * @param t              泛型对象
     * @param genDocLevelEvt 是否需要生成document level event（startDocument & endDocument）。对应Marshaller.JAXB_FRAGMENT。
     * @param <T>
     * @return
     */
    public static <T> StringWriter marshall(T t, boolean genDocLevelEvt) {
        StringWriter writer = new StringWriter();
        try {
            JAXBContext context = JAXBContext.newInstance(t.getClass());
            Marshaller marshaller = context.createMarshaller();
            setJAXB_FRAGMENT(marshaller, genDocLevelEvt);
            setJAXB_ENCODING(marshaller, "UTF-8");
            marshaller.marshal(t, writer);

        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
        return writer;
    }

    /**
     * @param jaxbElement       需要处理的对象
     * @param genDocLevelEvt    是否需要生成document level event（startDocument & endDocument）。对应Marshaller.JAXB_FRAGMENT。
     * @param bindingClass      bindingClass
     * @param doc               marshall后的内容输出到的Document对象
     * @return
     */
    public static void marshallByJAXBElement(JAXBElement jaxbElement, boolean genDocLevelEvt, Class bindingClass, Document doc) {
        try {
            JAXBContext context = JAXBContext.newInstance(bindingClass);
            Marshaller marshaller = context.createMarshaller();
            setJAXB_FRAGMENT(marshaller, genDocLevelEvt);
            setJAXB_ENCODING(marshaller, "UTF-8");
            marshaller.marshal(jaxbElement, doc);

        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param clazz 泛型对象的类
     * @param node  node
     * @param <T>
     * @return
     */
    public static <T> T unmarshall(Class<T> clazz, Node node) {
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            return (T) context.createUnmarshaller().unmarshal(node);
        } catch (JAXBException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置marshaller参数
     *
     * @param marshaller marshaller对象
     * @param val        会取反
     */
    private static void setJAXB_FRAGMENT(final Marshaller marshaller, boolean val) throws PropertyException {
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, !val);
    }

    /**
     * 设置marshaller参数
     *
     * @param marshaller
     * @param encoding
     */
    private static void setJAXB_ENCODING(Marshaller marshaller, String encoding) throws PropertyException {
        marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding);
    }
}
